package executor.impl;

import com.alibaba.fastjson.JSON;
import com.xiaoming.coupon.constant.CouponCategory;
import com.xiaoming.coupon.vo.GoodsInfo;
import com.xiaoming.coupon.vo.SettlementInfo;
import constant.RuleFlag;
import executor.AbstractExecutor;
import executor.RuleExecutor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 满减 + 折扣优惠券结算规则执行器
 * @author xiaoming
 * @Date 2020/6/23
 */
@Slf4j
@Component
public class ManJianZheKouExecutor extends AbstractExecutor implements RuleExecutor {
    /**
     * 规则类型标记
     * @return {@link RuleFlag}
     */
    @Override
    public RuleFlag ruleConfig() {
        return RuleFlag.MANJIAN_ZHEKOU;
    }

    /**
     * 校验商品类型与优惠券是否匹配
     * 需要注意：
     * 1.这里实现的满减 + 折扣优惠券的校验
     * 2.这里想要使用多类优惠券，则必须要所有的商品类型都包含在内，即差集为空
     * @param settlementInfo {@link SettlementInfo} 用户传递的计算信息
     * @return
     */
    @Override
    protected boolean isGoodsTypeSatify(SettlementInfo settlementInfo) {
        log.debug("Check ManJian And ZheKou Is Match Or Not");

        List<Integer> goodsType = settlementInfo.getGoodsInfos().stream()
                .map(GoodsInfo::getType).collect(Collectors.toList());
        List<Integer> templateGoodsType = new ArrayList<>();
        settlementInfo.getCouponAndTemplateInfos().forEach(ct -> {
            templateGoodsType.addAll(JSON.parseObject(
                    ct.getTemplate().getRule().getUsage().getGoodsType(), List.class
            ));
        });

        //如果想要使用多类优惠券，则必须要所有的商品类型都包含在内，即差集为空
        return CollectionUtils.isEmpty(CollectionUtils.subtract(
                goodsType, templateGoodsType
        ));
    }

    /**
     * 优惠券规则的计算
     * @param settlementInfo {@link SettlementInfo} 包含了选择的优惠券
     * @return {@link SettlementInfo} 修正过的结算信息
     */
    @Override
    public SettlementInfo computeRule(SettlementInfo settlementInfo) {
        double goodsSum = retain2Decimals(goodsCostSum(settlementInfo.getGoodsInfos()));
        SettlementInfo probability = processGoodsTypeNotSatify(settlementInfo, goodsSum);
        if (null != probability){
            log.debug("ManJian And ZheKou Template Is Not Match To GoodsType!");
            return probability;
        }

        SettlementInfo.CouponAndTemplateInfo manjian = null;
        SettlementInfo.CouponAndTemplateInfo zhekou = null;

        for (SettlementInfo.CouponAndTemplateInfo ct : settlementInfo.getCouponAndTemplateInfos()) {
            if (CouponCategory.of(ct.getTemplate().getCategory()) == CouponCategory.MANJIAN){
                manjian = ct;
            } else {
                zhekou = ct;
            }
        }

        assert null != manjian;
        assert null != zhekou;

        //当前的折扣优惠券和满减券如果不能一起使用，清空优惠券，返回商品原价
        if (!isTemplateCanShared(manjian, zhekou)){
            log.debug("Current ManJian And ZheKou Can Not Shared!");
            settlementInfo.setCost(goodsSum);
            settlementInfo.setCouponAndTemplateInfos(Collections.emptyList());
            return settlementInfo;
        }

        List<SettlementInfo.CouponAndTemplateInfo> ctInfos = new ArrayList<>();
        double manJianBase = manjian.getTemplate().getRule().getDiscount().getBase();
        double manJianQuota = manjian.getTemplate().getRule().getDiscount().getQuota();

        //最终的价格
        double targetSum = goodsSum;

        //先计算满减
        if (targetSum >= manJianBase){
            targetSum -= manJianQuota;
            ctInfos.add(manjian);
        }

        //再计算折扣
        double zheKouQuota = zhekou.getTemplate().getRule().getDiscount().getQuota();
        targetSum *= zheKouQuota * 1.0 /100;

        settlementInfo.setCouponAndTemplateInfos(ctInfos);
        settlementInfo.setCost(
                targetSum > minCost() ? targetSum : minCost()
        );

        log.debug("Use ManJian And ZheKou Coupon Make Goods Cost From {} To {}",
                goodsSum, settlementInfo.getCost());

        return settlementInfo;
    }


    /**
     * 当前两张优惠券是否可以共用
     * 即校验 TemplateRule 中的 weight 是否满足条件
     * @param manjian
     * @param zhekou
     * @return
     */
    private  boolean isTemplateCanShared(SettlementInfo.CouponAndTemplateInfo manjian,
                                         SettlementInfo.CouponAndTemplateInfo zhekou) {
        String manjianKey = manjian.getTemplate().getKey() + String.format("%04d", manjian.getTemplate().getId());
        String zhekouKey = zhekou.getTemplate().getKey() + String.format("$04d", zhekou.getTemplate().getId());

        List<String> allSharedKeysForManJian = new ArrayList<>();
        allSharedKeysForManJian.add(zhekouKey);
        allSharedKeysForManJian.addAll(JSON.parseObject(
                manjian.getTemplate().getRule().getWeight(), List.class
        ));

        List<String> allSharedKeysForZheKou = new ArrayList<>();
        allSharedKeysForZheKou.add(zhekouKey);
        allSharedKeysForZheKou.addAll(JSON.parseObject(
                zhekou.getTemplate().getRule().getWeight(), List.class
        ));

        return CollectionUtils.isSubCollection(
                Arrays.asList(manjianKey, zhekouKey), allSharedKeysForManJian
        ) || CollectionUtils.isSubCollection(
                Arrays.asList(manjianKey, zhekouKey), allSharedKeysForZheKou
        );
    }
}
